package com.lizhivscaomei.wms.application.service.sku;

import com.lizhivscaomei.wms.domain.entity.bills.inout.common.BizType;
import com.lizhivscaomei.wms.domain.entity.bills.inout.common.InOutType;
import com.lizhivscaomei.wms.domain.entity.bills.inout.common.bill.StockBillPassedEvent;
import com.lizhivscaomei.wms.domain.entity.bills.inout.common.bill.out.AbstractStockOutBill;
import com.lizhivscaomei.wms.domain.entity.bills.inout.common.bill.out.AbstractStockOutBillDetail;
import com.lizhivscaomei.wms.domain.entity.bills.inout.produce.finished.in.ProductInBill;
import com.lizhivscaomei.wms.domain.entity.bills.inout.produce.raw.in.bill.RawDistReturnInBill;
import com.lizhivscaomei.wms.domain.entity.bills.inout.produce.wip.in.WipInBill;
import com.lizhivscaomei.wms.domain.entity.bills.inout.purchase.in.bill.PurchaseInBill;
import com.lizhivscaomei.wms.domain.entity.bills.inout.sale.in.bill.SaleReturnInBill;
import com.lizhivscaomei.wms.domain.entity.sku.Sku;
import com.lizhivscaomei.wms.domain.entity.sku.SkuRepo;
import com.lizhivscaomei.wms.domain.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.List;

@Service
public class SkuManager {
    @Autowired
    private StockService stockService;
    @Autowired
    private SkuRepo skuRepo;
    @Autowired
    private SkuQueryService skuQueryService;

    @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
    public void dealBillPassedEvent(StockBillPassedEvent event) throws Exception {
        if (event.getBill().getInOutType().equals(InOutType.OUT)) {
            if (!event.getBill().getBizType().equals(BizType.OTHER)) {
                this.skuQueryService.checkFifo((AbstractStockOutBill) event.getBill());
            }
            this.subtractStock((AbstractStockOutBill) event.getBill());
        } else {
            if (event.getBill().getBizType().equals(BizType.PURCHASE)) {
                List<Sku> skuList = this.stockService.inBillToSkus((PurchaseInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.SALE)) {
                List<Sku> skuList = this.stockService.inBillToSkus((SaleReturnInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.PRODUCE_RAW_DIST)) {
                List<Sku> skuList = this.stockService.inBillToSkus((RawDistReturnInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.PRODUCE_WIP)) {
                List<Sku> skuList = this.stockService.inBillToSkus((SaleReturnInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.PRODUCE_PRODUCT)) {
                List<Sku> skuList = this.stockService.inBillToSkus((ProductInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.PRODUCE_WIP)) {
                List<Sku> skuList = this.stockService.inBillToSkus((WipInBill) event.getBill());
                this.addStock(skuList);
            } else if (event.getBill().getBizType().equals(BizType.OTHER)) {
                List<Sku> skuList = this.stockService.inBillToSkus((SaleReturnInBill) event.getBill());
                this.addStock(skuList);
            } else {
                throw new Exception("不支持的单据类型");
            }
        }
    }


    /**
     * 加库存
     *
     * @param skuList 库存信息
     */
    private void addStock(List<Sku> skuList) {
        this.skuRepo.saveAll(skuList);
    }

    /**
     * 减库存
     *
     * @param outBill 出库单
     * @throws Exception 异常
     */
    private void subtractStock(AbstractStockOutBill outBill) throws Exception {
        List<AbstractStockOutBillDetail> details = outBill.getDetails();
        for (AbstractStockOutBillDetail detail : details) {
            Sku sku = this.skuRepo.getOne(detail.getSkuId());
            boolean isEmpty = sku.subtract(detail.getNumber());
            if (isEmpty) {
                this.skuRepo.delete(sku);
            } else {
                this.skuRepo.save(sku);
            }
        }
    }
}
